package xj.graph2d.template.uml;

import xj.graph2d.AbstractModelListener;
import xj.graph2d.Arrow;
import xj.graph2d.DrawShape;
import xj.graph2d.DrawShapeConstants;
import xj.graph2d.GraphEdgeBase;
import xj.graph2d.Label;
import xj.graph2d.OpenShape;
import xj.graph2d.TextShape;
import xj.graph2d.template.UMLClassDiagramTemplate;
import xj.graph2d.template.UMLTemplate;
import xj.model.uml.Multiplicity;
import xj.model.uml.Navigability;
import xj.model.uml.UMLAssociation;
import xj.model.uml.UMLAssociationEnd;

public class UMLAssociationModelListener 
  extends AbstractModelListener {

  public UMLAssociationModelListener() {
  }

  public UMLAssociationModelListener(UMLTemplate template) {
    this(null, null, template);
  }

  public UMLAssociationModelListener(Object model, 
				     DrawShape shape,
				     UMLTemplate template) {
    super(model, shape);
    this.template = template;
  }

  @Override
  public void updateModel() {
    if (shape instanceof GraphEdgeBase && model instanceof UMLAssociation) {
      GraphEdgeBase assoc = (GraphEdgeBase) shape;
      UMLAssociation assocmodel = (UMLAssociation) model;

      if (debug) {
	System.out.println("UMLAssociationModelListener.updateModel() @1");
	System.out.println("   model: UMLAssociation navRight=" + 
			   assocmodel.getNavigabilityToRight() + 
			   "  navLeft=" + assocmodel.getNavigabilityToLeft());
      }

      String name = assoc.getLabel(DrawShapeConstants.ROLE_EDGE_LABEL);
      assocmodel.setName(name);
      String leftRole = assoc.getLabel(DrawShapeConstants.ROLE_EDGE_TAIL_LABEL);
      assocmodel.setLeftRole(leftRole);
      String leftMulti = assoc.getLabel(DrawShapeConstants.ROLE_EDGE_TAIL_LABEL2);
      assocmodel.setLeftMultiplicity(Multiplicity.toMultiplicity(leftMulti));
      String rightRole = assoc.getLabel(DrawShapeConstants.ROLE_EDGE_HEAD_LABEL);
      assocmodel.setRightRole(rightRole);
      String rightMulti = assoc.getLabel(DrawShapeConstants.ROLE_EDGE_HEAD_LABEL2);
      assocmodel.setRightMultiplicity(Multiplicity.toMultiplicity(rightMulti));
      Navigability navRight = Navigability.Default;
      Navigability navLeft = Navigability.Default;
      UMLAssociationEnd.AggregationKind aggRight = UMLAssociationEnd.AggregationKind.None;
      UMLAssociationEnd.AggregationKind aggLeft = UMLAssociationEnd.AggregationKind.None;
      if (shape instanceof OpenShape && 
	  (assocmodel.getType() == UMLAssociation.AssociationType.Association || 
	   assocmodel.getType() == UMLAssociation.AssociationType.Aggregation || 
	   assocmodel.getType() == UMLAssociation.AssociationType.Composition)) {
	OpenShape edge = (OpenShape) shape;
	Arrow head = edge.getHeadArrow();
	if (head != null) {
	  if (head.getType() != null) {
	    switch (head.getType()) {
	    case LineArrow:
	      navRight = Navigability.Navigable;
	      break;

	    case XArrow:
	      navRight = Navigability.NonNavigable;
	      break;

	    case HollowDiamondArrow:
	      navRight = Navigability.Navigable;
	      aggRight = UMLAssociationEnd.AggregationKind.Shared;
	      break;

	    case HollowDiamondX:
	      navRight = Navigability.NonNavigable;
	      aggRight = UMLAssociationEnd.AggregationKind.Shared;
	      break;

	    case HollowDiamond:
	      aggRight = UMLAssociationEnd.AggregationKind.Shared;
	      break;

	    case FilledDiamondArrow:
	      navRight = Navigability.Navigable;
	      aggRight = UMLAssociationEnd.AggregationKind.Composite;
	      break;

	    case FilledDiamondX:
	      navRight = Navigability.NonNavigable;
	      aggRight = UMLAssociationEnd.AggregationKind.Composite;
	      break;

	    case FilledDiamond:
	      aggRight = UMLAssociationEnd.AggregationKind.Composite;
	      break;
	    }
	  }
	}
	Arrow tail = edge.getTailArrow();
	if (tail != null) {
	  if (tail.getType() != null) {
	    switch (tail.getType()) {
	    case LineArrow:
	      navLeft = Navigability.Navigable;
	      break;

	    case XArrow:
	      navLeft = Navigability.NonNavigable;
	      break;

	    case HollowDiamondArrow:
	      navLeft = Navigability.Navigable;
	      aggLeft = UMLAssociationEnd.AggregationKind.Shared;
	      break;

	    case HollowDiamondX:
	      navLeft = Navigability.NonNavigable;
	      aggLeft = UMLAssociationEnd.AggregationKind.Shared;
	      break;

	    case HollowDiamond:
	      aggLeft = UMLAssociationEnd.AggregationKind.Shared;
	      break;

	    case FilledDiamondArrow:
	      navLeft = Navigability.Navigable;
	      aggLeft = UMLAssociationEnd.AggregationKind.Composite;
	      break;

	    case FilledDiamondX:
	      navLeft = Navigability.NonNavigable;
	      aggLeft = UMLAssociationEnd.AggregationKind.Composite;
	      break;

	    case FilledDiamond:
	      aggLeft = UMLAssociationEnd.AggregationKind.Composite;
	      break;
	    }
	  }
	}
      }
      assocmodel.setNavigabilityToRight(navRight);
      assocmodel.setNavigabilityToLeft(navLeft);
      assocmodel.setRightAggregation(aggRight);
      assocmodel.setLeftAggregation(aggLeft);

      if (debug) {
	System.out.println("UMLAssociationModelListener.updateModel() @2");
	System.out.println("   model: UMLAssociation navRight=" + assocmodel.getNavigabilityToRight() + 
			   "  navLeft=" + assocmodel.getNavigabilityToLeft());
      }
    }
  }

  @Override
  public void updateShape() {
    if (debug) {
      System.out.println("UMLAssociationModelListener.updateShape()");
    }

    if (shape instanceof GraphEdgeBase && model instanceof UMLAssociation) {
      GraphEdgeBase assoc = (GraphEdgeBase) shape;
      UMLAssociation assocmodel = (UMLAssociation) model;
      String name = assocmodel.getName();
      if (name != null) {
	setLabel(assoc, DrawShapeConstants.ROLE_EDGE_LABEL, name, "Name");
      }
      String leftRole = assocmodel.getLeftRole();
      if (leftRole != null) {
	setLabel(assoc, DrawShapeConstants.ROLE_EDGE_TAIL_LABEL, leftRole,
		 "End 1 role"); // left
      }
      String leftMulti = Multiplicity.toString(assocmodel.getLeftMultiplicity());
      if (leftMulti != null) {
	setLabel(assoc, DrawShapeConstants.ROLE_EDGE_TAIL_LABEL2, leftMulti,
		 "End 1 multiplicity"); // left
      }
      String rightRole = assocmodel.getRightRole();
      if (rightRole != null) {
	setLabel(assoc, DrawShapeConstants.ROLE_EDGE_HEAD_LABEL, rightRole,
		 "End 2 role"); // right
      }
      String rightMulti = Multiplicity.toString(assocmodel.getRightMultiplicity());
      if (rightMulti != null) {
	setLabel(assoc, DrawShapeConstants.ROLE_EDGE_HEAD_LABEL2, rightMulti,
		 "End 2 multiplicity"); // right
      }

      if (shape instanceof OpenShape) {
	OpenShape edge = (OpenShape) shape;
	Navigability navRight = assocmodel.getNavigabilityToRight();
	Navigability navLeft = assocmodel.getNavigabilityToLeft();
	UMLAssociationEnd.AggregationKind aggRight = assocmodel.getRightAggregation();
	UMLAssociationEnd.AggregationKind aggLeft = assocmodel.getLeftAggregation();
	template.setNavigabilityArrows(edge, navRight, aggRight, navLeft, aggLeft);
      }
    }
  }

  protected void setLabel(GraphEdgeBase assoc, int role, String label) {
    setLabel(assoc, role, label, null);
  }

  protected void setLabel(GraphEdgeBase assoc, int role, String label,
      String displayName) {
    if (assoc != null) {
      Label curLabel = assoc.getLabelShape(role);
      if (curLabel != null) {
	if (label != null && label.length() > 0) {
	  curLabel.setText(label);
	  if (displayName != null) {
	    curLabel.setDisplayName(displayName);
	  }
	} else {
	  assoc.removeLabel(curLabel);
	}
      } else {
	if (label != null && label.length() > 0) {
	  String prompt;
	  boolean multi = true;
	  switch (role) {
	  case DrawShapeConstants.ROLE_EDGE_TAIL_LABEL:
	  case DrawShapeConstants.ROLE_EDGE_HEAD_LABEL:
	    prompt = "role";
	    break;
	  case DrawShapeConstants.ROLE_EDGE_TAIL_LABEL2:
	  case DrawShapeConstants.ROLE_EDGE_HEAD_LABEL2:
	    prompt = "multiplicity";
	    multi = false;
	    break;
	  case DrawShapeConstants.ROLE_EDGE_LABEL:
	  default:
	    prompt = "association";
	    break;
	  }

	  TextShape labelShape;
	  if (template != null) {
	    labelShape = template.makeContentText(label, prompt, multi,
						  UMLClassDiagramTemplate.ASSOCIATION_LABEL_FONT,
						  UMLClassDiagramTemplate.ASSOCIATION_LABEL_COLOR);
	  } else {
	    labelShape = new TextShape(label);
	    labelShape.setPrompt((prompt != null) ? prompt : "text");
	    labelShape.setAllowMultiLine(multi);
	    labelShape.setDetachable(false);
	    labelShape.setScalable(false);
	    labelShape.showCursor(true);
	  }
	  labelShape.setMovable(true);
	  labelShape.setSticky(false);

	  if (debug) {
	    System.out.println("UMLAssociationModelListener.setLabel() isDetachable="
			       + labelShape.isDetachable());
	  }

	  if (displayName != null) {
	    labelShape.setDisplayName(displayName);
	  }
	  assoc.setLabel(role, labelShape);
	}
      }
    }
  }

  protected UMLTemplate template;

  protected static final boolean debug = false;

}
